/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hiof.moraa.server.dao;

import com.hiof.moraa.mapping.TblSupport;
import com.hiof.moraa.mapping.TblSupportLiveLocation;
import com.hiof.moraa.server.service.model.Feed;
import com.hiof.moraa.server.service.model.LiveLocationFeed;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Bergy
 */
public class HibernateSupportLiveLocationDAOImp implements SupportLiveLocationDAO {

    private SessionFactory factory;

    public SessionFactory getFactory() {
        return factory;
    }

    public void setFactory(SessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public LiveLocationFeed insertSupportLiveLocationFeed(int supportId, double lat, double lng, double height, double speed, Timestamp timestamp) {
        TblSupportLiveLocation supportLiveLocation = new TblSupportLiveLocation();
        try {
            TblSupport support = (TblSupport) factory.getCurrentSession().get(TblSupport.class, supportId);
            supportLiveLocation.setTblSupport(support);
            supportLiveLocation.setHeight(height);
            supportLiveLocation.setLat(lat);
            supportLiveLocation.setLng(lng);
            supportLiveLocation.setSpeed(speed);
            supportLiveLocation.setTimeStamp(timestamp);

            factory.getCurrentSession().save(supportLiveLocation);
        } catch (HibernateException e) {
            Logger.getLogger(HibernateSupportLiveLocationDAOImp.class.getName()).log(Level.SEVERE, "Hibernate Exception Occured", e);
        }

        LiveLocationFeed supportLocationFeed = convert2LiveLocationFeed(supportLiveLocation);
        return supportLocationFeed;
    }

    @Override
    public List<LiveLocationFeed> getLiveLocationFeedOfSupportByUsername(String username, int routeId) {
        try {
            Session session = factory.getCurrentSession();

            String hql = "from TblSupportLiveLocation location where location.tblSupport.tblUser.username = :username and location.tblSupport.tblRoute.id = :routeId "
                    + "order by location.timeStamp desc";
            Query query = session.createQuery(hql);
            query.setString("username", username);
            query.setInteger("routeId", routeId);
            List<TblSupportLiveLocation> supportLiveLocations = query.list();

            List<LiveLocationFeed> result = fetchToLiveMediaLocationList(supportLiveLocations);
            supportLiveLocations.clear();
            return result;
        } catch (Exception ex) {
            return new ArrayList<LiveLocationFeed>();
        }
    }

    @Override
    public List<LiveLocationFeed> getLatestLiveLocationFeedOfAllSupport(int routeId) {
        Session session = factory.getCurrentSession();
        List<LiveLocationFeed> result = new ArrayList<LiveLocationFeed>();
        String sql = new StringBuilder().append("select * from ( \n").append("    select support_id, max(timeStamp) as timeStamp \n").append("    from tbl_support_live_location, tbl_support \n").append("    where tbl_support.route_id = :routeId and tbl_support.id = tbl_support_live_location.support_id \n").append("    group by support_id \n").append(") as groupTable inner join tbl_support_live_location as support \n").append("on support.support_id = groupTable.support_id and support.timeStamp = groupTable.timeStamp; \n").toString();

        Query query = session.createSQLQuery(sql).addEntity(TblSupportLiveLocation.class);
        List liveLocations = query.setInteger("routeId", routeId).list();

        for (Iterator it = liveLocations.iterator(); it.hasNext(); ) {
            TblSupportLiveLocation liveLocation = (TblSupportLiveLocation) it.next();
            result.add(convert2LiveLocationFeed(liveLocation));
        }
        return result;
    }

    @Override
    public List<LiveLocationFeed> getLatestLiveLocationFeedOfSupportInOneRoute(int routeId, int numOfFeed) {
        Session session = factory.getCurrentSession();

        String hql = "from TblSupportLiveLocation location where location.tblSupport.tblRoute.id = :routeId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setInteger("routeId", routeId);
        query.setMaxResults(numOfFeed);
        List<TblSupportLiveLocation> supportLiveLocations = query.list();

        List<LiveLocationFeed> result = fetchToLiveMediaLocationList(supportLiveLocations);
        supportLiveLocations.clear();
        return result;
    }

    @Override
    public Collection<? extends Feed> getLatestLiveLocationFeedOfOneUsertInOneRoute(String username, int routeId, int numOfLiveLocationFeed) {
        Session session = factory.getCurrentSession();

        String hql = "from TblSupportLiveLocation location where location.tblSupport.tblUser.username = :username and location.tblSupport.tblRoute.id = :routeId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setString("username", username);
        query.setInteger("routeId", routeId);
        query.setMaxResults(numOfLiveLocationFeed);
        List<TblSupportLiveLocation> supportLiveLocations = query.list();

        List<LiveLocationFeed> result = fetchToLiveMediaLocationList(supportLiveLocations);
        supportLiveLocations.clear();
        return result;
    }

    @Override
    public LiveLocationFeed getLatestLiveLocationFeedOfOneSupport(int supportId) {
        Session session = factory.getCurrentSession();

        String hql = "from TblSupportLiveLocation location where location.tblSupport.id = :supportId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setInteger("supportId", supportId);
        query.setMaxResults(1);
        TblSupportLiveLocation supportLiveLocation = (TblSupportLiveLocation) query.uniqueResult();
        return convert2LiveLocationFeed(supportLiveLocation);
    }

    private List<LiveLocationFeed> fetchToLiveMediaLocationList(List<TblSupportLiveLocation> supportLiveLocations) {
        List<LiveLocationFeed> result = new ArrayList<LiveLocationFeed>();
        for (TblSupportLiveLocation location : supportLiveLocations) {
            result.add(convert2LiveLocationFeed(location));
        }
        return result;
    }

    private LiveLocationFeed convert2LiveLocationFeed(TblSupportLiveLocation supportLiveLocation) {
        if(supportLiveLocation == null)
            return null;
        LiveLocationFeed supportLocationFeed = new LiveLocationFeed(
                supportLiveLocation.getTblSupport().getTblUser().getId(),
                supportLiveLocation.getTblSupport().getTblUser().getUsername(),
                supportLiveLocation.getTblSupport().getTblUser().getFirstName() + " " + supportLiveLocation.getTblSupport().getTblUser().getLastName(),
                supportLiveLocation.getTblSupport().getTblUser().getProfilePicture(),
                supportLiveLocation.getTimeStamp(),
                supportLiveLocation.getTblSupport().getAttendantCode(),
                supportLiveLocation.getLat(), supportLiveLocation.getLng(),
                supportLiveLocation.getHeight(), supportLiveLocation.getSpeed());
        return supportLocationFeed;
    }
}
